<?php

/*******************************************************************************
 * 
 * CLASS [ELEMENT]
 * 
 *******************************************************************************
 * 
 * @package phutile
 * @author Stanislas PERRIN <stanislas.perrin@gmail.com> <stan@extramuros.com>
 * @licence LGPL v3 
 * 
 ******************************************************************************/

abstract class element 
{
	############################################################################
	#
	# PROPERTIES
	#
	############################################################################
	
	protected $name = null; // string -- element name
	
	protected $openingTag = null; // string -- opening of the tag
	protected $closingTag = null; // string -- closing of the tag
	
	protected $attributes = array(); // associative array -- attributes of the element
	
	protected $selfClosingTag = false; // boolean -- is the tag of the element is self-closing ?
	
	protected $block = true; // boolean -- is the element a "block" element or an "inline" one ?
	
	protected $indentCounter = 0;
	
	protected $content = null; // mixed -- (x)html element content (possibly string, array of string, object or array of objects)
	
	protected $_CR = "\n";
	protected $_TAB = "\t";
	protected $_CR_TAB = "\n\t";
	
	############################################################################
	#
	# CONSTRUCTOR
	#
	############################################################################
	
	public function __construct($elementName=false,$selfClosingTag=false,$block=true)
	{
		if (!$elementName) throw new debug(-999,'missing element name');
		
		$elementName = strtolower($elementName);
		$this->name = $elementName;
		
		$this->setSelfClosingTag($selfClosingTag);
		
		$this->block = $block;
				
		if ($this->selfClosingTag)
		{
			$this->setOpeningTag("<{$this->name}");
			$this->setClosingTag(" />");
		}
		else
		{
			$this->setOpeningTag("<{$this->name}>");
			$this->setClosingTag("</{$this->name}>");
		}
	}

	############################################################################
	#
	# PUBLIC METHODS
	#
	############################################################################
	
	public function render()
	{
		print($this->preRender());
	}

	############################################################################
	#
	# PROTECTED METHODS
	#
	############################################################################
	
	protected function setOpeningTag($tag=false)
	{
		if (!$tag) throw new debug(get_class($this) . 'missing opening tag', -999);
		$this->openingTag = $tag;
	}
	
	protected function setClosingTag($tag=false)
	{
		if (!$tag) throw new debug(get_class($this) . 'missing closing tag',-999);
		$this->closingTag = $tag;
	}
	
	protected function setContent($content='')
	{
		// element may be empty so $content could be an empty string
		$this->content = $content;
	}
	
	protected function setSelfClosingTag($selfClosing=false)
	{
		$this->selfClosingTag = $selfClosing;
	}
	
	public function setAttribute($attributeName=false,$attributeValue=false)
	{
		if (!$attributeName) throw new debug(get_class($this) . 'missing attribute name',-999);
		// if (!$attributeValue) throw new debug(get_class($this) . 'missing attribute value',-999);
		
		$attributeName = strtolower($attributeName);
		
		$this->attributes[$attributeName] = $attributeValue;
		
		// Updating the opening tag !
		// $this->updateOpeningTag();
	}
	
	public function setAttributes($attributes=false)
	{
		if (!$attributes) throw new debug(get_class($this) . 'missing attributes',-999);
		
		$this->attributes = array_merge($this->attributes,$attributes);
		
		// Updating the opening tag !
		$this->updateOpeningTag();
	}
	
	protected function updateOpeningTag()
	{
		// Updating the opening tag !
		if ($this->selfClosingTag)
		{
			$this->setOpeningTag('<' . $this->name . ' ' . $this->serializeAttributes());
		}
		else
		{
			$this->setOpeningTag('<' . $this->name . ' ' . $this->serializeAttributes() . '>');
		}
		// if (!$result) throw new debug(get_class($this) . 'cant update opening tag',-999);
	}
	
	protected function serializeAttributes()
	{
		$strAttributes = '';
		
		foreach ($this->attributes as $attributeName => $attributeValue)
		{
			$strAttributes .= "$attributeName=\"$attributeValue\" ";
		}
		
		return $strAttributes;
	}
	
	/**
	 * preRender()
	 * 
	 * Build the element in a string and return it. It actually does not really 
	 * render
	 * 
	 * @param void
	 * @return string The string containing the <element>
	 * 
	 */
	public function preRender()
	{
		if ($this->selfClosingTag)
		{
			$strFinalRendering = $this->openingTag . $this->serializeAttributes() . $this->closingTag;
		}
		else
		{
			if ($this->block)
			{
				$strFinalRendering = $this->_CR . $this->openingTag
								   . $this->_CR_TAB . $this->contentRender($this->content)
								   . $this->_CR . $this->closingTag
								   . $this->_CR;
			}
			else
			{
				$strFinalRendering = $this->openingTag . $this->contentRender($this->content) . $this->closingTag;
			}
		}
		
		return $strFinalRendering;
	}
		
	
	/**
	 * 
	 * contentRender();
	 * 
	 * Return a string rendering of an element content. Recursively explore
	 * complex contents such as arrays of text or, evev, arrays of objects
	 * (or arrays of arrays of arrays of objects).
	 * This method return the content of ALL included (child) element-objects.
	 * 
	 * @param mixed $content Anything that looks like an element content
	 * @return string A string rendering of the $content
	 * 
	 */
	
	protected function contentRender($content='')
	{
		// if (!$content) throw new debug(get_class($this) . 'missing content',-999);
		$this->indentCounter++;
		
		if (is_string($content)) return $content;
		if (is_object($content)) return $content->preRender();
		if (is_array($content))
		{
			$strTemp = '';
			foreach($content as $line)
			{
				$strTemp .= $this->contentRender($line);
			}
			
			return $strTemp;
		}
	}
	
	############################################################################
	#
	# PRIVATE METHODS
	#
	############################################################################

}


?>
